import 'reflect-metadata'

function Injectable() {
  return function (target: any) {
    // 保留原始类，不做修改
    console.log(target)
  }
}

@Injectable()
class Light {
  toLight() {
    console.log('我会发光')
  }
}

@Injectable()
class Car {
  constructor(private light: Light) {}
  drive() {
    this.light.toLight()
    console.log('我会开车')
  }
}

class IOC {
  private container = new Map<string, any>()

  register<T>(name: string, Service: new (...args: any[]) => T) {
    this.container.set(name, Service)
  }

  resolve(name: string) {
    const Service = this.container.get(name)
    if (!Service) {
      throw new Error(`依赖 ${name} 未注册`)
    }

    const paramTypes = Reflect.getMetadata('design:paramtypes', Service) || []

    const dependencies = paramTypes.map((paramType: any) => {
      // 使用构造函数名称作为依赖名称
      const dependencyName = paramType.name
      return this.resolve(dependencyName)
    })

    return new Service(...dependencies)
  }
}

// 启用反射元数据
// Reflect.defineMetadata = Reflect.defineMetadata || function () {}

const ioc = new IOC()
ioc.register('Light', Light)
ioc.register('Car', Car)
const car = ioc.resolve('Car')
car.drive()
